package com.heima.wemedia.service.impl;

import com.heima.article.feign.ApArticleFeign;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.RedisConstants;
import com.heima.common.dtos.ResponseResult;
import com.heima.common.minio.MinIOFileStorageService;
import com.heima.model.article.dtos.ApArticleDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.BeanHelper;
import com.heima.utils.common.JsonUtils;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsTaskService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import net.sourceforge.tess4j.ITesseract;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 自动审核文章接口实现类
 */
@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired
    private MinIOFileStorageService fileStorageService;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private ApArticleFeign apArticleFeign;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmUserMapper wmUserMapper;

    @Autowired
    private WmChannelMapper wmChannelMapper;

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private ITesseract tesseract;

    @Autowired
    private WmNewsTaskService wmNewsTaskService;


    /**
     * 自动审核文章
     */
    @Override
    @Async  //这是一个异步方法
    @GlobalTransactional  //分布式事务
    public void autoScanWmNews(WmNews wmNews) {
        //判断当前是否为审核状态
        //不是审核状态跳过
        if (wmNews.getStatus() != 1) {
            return;
        }

        //提取文章的文字
        List<String> text = getTestOrImgFromWmNews(wmNews, "text");

        //提取文章的图片
        List<String> image = getTestOrImgFromWmNews(wmNews, "image");
        List<byte[]> byteImages = getByteImagesFromImage(image);

        //OCR识别图片文字
        getTestForImages(byteImages,text);

        //自定义敏感词检测
        if (CollectionUtils.isNotEmpty(text)) {
            boolean flag = handleSensitiveScan(text, wmNews);
            if (!flag) {
                return;
            }
        }


        //调用阿里云接口审核文字
        if (CollectionUtils.isNotEmpty(text)) {
            try {
                val result = greenTextScan.greeTextScan(text);

                //对阿里云结果处理
                boolean flag = handleScanResult(result, wmNews);
                if (!flag) {
                    return; // 如果审核不过，则无需往下执行
                }
            } catch (Exception e) {
                log.info("审核文字失败:" + e);
                throw new RuntimeException(e);
            }
        }


        //调用阿里云接口审核图片
        if (CollectionUtils.isNotEmpty(byteImages)) {
            try {
                val result = greenImageScan.imageScan(byteImages);
                //对阿里云结果处理
                boolean flag = handleScanResult(result, wmNews);
                if (!flag) {
                    return; // 如果审核不过，则无需往下执行
                }
            } catch (Exception e) {
                log.info("审核图片失败:" + e);
                throw new RuntimeException(e);
            }
        }


        //判断用户选择的发布时间是否大于当前时间
        if (wmNews.getCreatedTime() != null && wmNews.getCreatedTime().after(new Date())) {
            //修改文章状态为8（待发布）
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
            wmNews.setReason("文章审核通过，进入定时发布队列");
            wmNewsMapper.updateById(wmNews);

            //把当前自媒体文章发布任务添加到延迟队列中
            Long taskId = wmNewsTaskService.addWmNewsTask(wmNews);

            //更新wm_news表的task_id字段
            return;
        }

        //调用Feign接口保存App文章
        publishApArticle(wmNews);
    }


    /**
     * OCR识别图片文字
     */
    private void getTestForImages(List<byte[]> byteImages, List<String> text) {
        if (CollectionUtils.isNotEmpty(byteImages)){
            //遍历图片
            for (byte[] byteImage : byteImages) {
                try {
                    //将二进制普片转换为输入流
                    ByteArrayInputStream inputStream = new ByteArrayInputStream(byteImage);
                    BufferedImage bufferedImage = ImageIO.read(inputStream);
                    //返回文本
                    String result = tesseract.doOCR(bufferedImage);
                    if (StringUtils.isNotEmpty(result)){
                        text.add(result);
                    }
                } catch (Exception e) {
                    log.info("图片读取失败:{}",e.getMessage());
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 自定义敏感词检测
     */
    private boolean handleSensitiveScan(List<String> textList, WmNews wmNews) {
        boolean flag = true;

        //从redis查询数据
        List<String> wordList = null;
        String redisData = redisTemplate.opsForValue().get(RedisConstants.SENSITIVE_WORD);

        //redis没缓存
        if (redisData == null) {
            //从数据库中查出自定义敏感词
            List<WmSensitive> sensitiveList = wmSensitiveMapper.selectList(null);
            if (CollectionUtils.isNotEmpty(sensitiveList)){
                wordList = sensitiveList.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            }
            //将铭感词列表放入Redis中
            redisTemplate.opsForValue().set(RedisConstants.SENSITIVE_WORD, JsonUtils.toString(wordList));
        }else{
            //redis有缓存情况
            wordList = JsonUtils.toList(redisData, String.class);
        }

        //将敏感词放入关键词字典库
        SensitiveWordUtil.initMap(wordList);

        //判断的参数不为空
        if (CollectionUtils.isNotEmpty(textList)) {
            //将文字列表拼接检测
            String content = String.join("", textList);
            //去除空格
            content = content.replaceAll(" ","");
            //检测内容出现的关键字和频率
            Map<String, Integer> result = SensitiveWordUtil.matchWords(content);

            if (result != null && result.size() > 0) {
                //获取违规词
                Set<String> keys = result.keySet();
                //修改文章状态
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章包含违规词：" + keys);
                wmNewsMapper.updateById(wmNews);
                flag = false;
            }
        }
        return flag;
    }


    //提取文章和标题或者图片的列表
    private List<String> getTestOrImgFromWmNews(WmNews wmNews, String type) {
        //文章或者图片的集合
        List<String> list = new ArrayList<>();


        //如果是文本获取标题
        if (StringUtils.isNotBlank(wmNews.getTitle()) && type.equals("text")) {
            list.add(wmNews.getTitle());
        }
        //标签
        if (StringUtils.isNotBlank(wmNews.getLabels()) && type.equals("text")) {
            list.add(wmNews.getLabels());
        }

        //如果是图片获取标题图片
        if (StringUtils.isNotBlank(wmNews.getImages()) && type.equals("image")) {
            list.addAll(Arrays.asList(wmNews.getImages().split(",")));
        }

        if (StringUtils.isNotBlank(wmNews.getContent())) {
            //获取文章所有的内容
            val maps = JsonUtils.toList(wmNews.getContent(), Map.class);
            //区分文章或图片

            assert maps != null;
            list.addAll(maps.stream()
                    .filter(map -> map.get("type").equals(type))
                    .map(map -> (String) map.get("value"))
                    .collect(Collectors.toList()));
        }
        return list;
    }


    //根据图片地址到MinIO下载所有图片
    private List<byte[]> getByteImagesFromImage(List<String> images) {
        List<byte[]> byteImages = new ArrayList<>();
        for (String image : images) {
            byte[] bytes = fileStorageService.downLoadFile(image);
            if (bytes != null) {
                byteImages.add(bytes);
            }
        }
        return byteImages;
    }


    //阿里云资源鉴定
    private boolean handleScanResult(Map result, WmNews wmNews) {
        boolean flag = false;

        //取出阿里云结果
        String suggestion = (String) result.get("suggestion");
        if (StringUtils.isNotBlank(suggestion)) {
            if ("block".equals(suggestion)) {
                //修改文章状态为失败
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章包含违规内容,请自行检查内容");
                wmNewsMapper.updateById(wmNews);
            }
            //机器无法审核把状态转交给人工
            if ("review".equals(suggestion)) {
                //修改文章状态为人工
                wmNews.setStatus(WmNews.Status.NORMAL.getCode());
                wmNews.setReason("该文章需要进一步审核,请稍后");
                wmNewsMapper.updateById(wmNews);
            }
            if ("pass".equals(suggestion)) {
                flag = true;
            }
        }
        return flag;
    }


    //远程调用保存文章
    @GlobalTransactional
    public void publishApArticle(WmNews wmNews) {
        //拷贝属性
        ApArticleDto dto = BeanHelper.copyProperties(wmNews, ApArticleDto.class);

        //重要代码：====重新绑定ap_article表的id====
        assert dto != null;
        dto.setId(wmNews.getArticleId());

        //设置文章作者信息
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            dto.setAuthorId(Long.valueOf(wmUser.getId()));   //设置作者id
            dto.setAuthorName(wmUser.getNickname());         //设置作者姓名
        }
        //设置文章频道信息
        WmChannel channel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (channel != null) {
            dto.setChannelId(channel.getId());               //设置频道的id
            dto.setChannelName(channel.getName());           //设置频道的名字
        }
        //设置封面类型
        dto.setLayout(wmNews.getType());
        //设置文章类型
        dto.setFlag((byte) 0);
        //设置文章参数
        dto.setLikes(0);
        dto.setViews(0);
        dto.setComment(0);
        dto.setCollection(0);

        ResponseResult<Long> responseResult = apArticleFeign.save(dto);
        if (responseResult.getCode().equals(200)) {
            //获取App的文章ID
            Long articleId = responseResult.getData();

            //设置自媒体文章的article_id
            wmNews.setArticleId(articleId);
            //修改文章状态为9（已发布）
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setReason("文章已成功发布");
            wmNewsMapper.updateById(wmNews);
        }
    }

}
